﻿/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include"highlight/myhighlighter.h"
#include"showhtml.h"

#include <QFile>
#include <QFileDialog>
#include <QFontDatabase>
#include <QMessageBox>
#include<QFontDialog>
#include<QFont>
#include<QtDebug>
#include <QCloseEvent>
#include<QInputDialog>
#include<QMimeData>
#include<QtPrintSupport/QPrinter>
#include<QTextDocumentWriter>
#include<QMimeDatabase>

#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#include <QStringDecoder>
#include <QStringEncoder>
#endif

MainWindow::MainWindow(QWidget *parent,const QString &path) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/3rdparty/breeze-icon/default.png"));
    //编辑器用系统字体
    ui->editor->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
    //允许拖放
    setAcceptDrops(true);
    //喵高亮系统
    MyHighLighter *high = new MyHighLighter(ui->editor->document());





    //如果接收到改变内容的信号，就把新内容发送给m_content，一个继承自Qobject的document类
    //connect(ui->editor, &QPlainTextEdit::textChanged,this,SLOT());



    //文件菜单
    connect(ui->actionNew, &QAction::triggered, this, &MainWindow::onFileNew);
    connect(ui->actionNew_2, &QAction::triggered, this, &MainWindow::onFileNew);
    connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::onFileOpen);
    connect(ui->actionOpen_2, &QAction::triggered, this, &MainWindow::onFileOpen);
    connect(ui->actionSave, &QAction::triggered, this, &MainWindow::onFileSave);
    connect(ui->actionSave_2, &QAction::triggered, this, &MainWindow::onFileSave);
    connect(ui->actionSaveAs, &QAction::triggered, this, &MainWindow::onFileSaveAs);
    connect(ui->actionFont,&QAction::triggered,this,&MainWindow::ChangeFont);
    connect(ui->actionFind,&QAction::triggered,this,&MainWindow::Findsome);

    connect(ui->editor->document(), &QTextDocument::modificationChanged,
            ui->actionSave, &QAction::setEnabled);
    connect(ui->actionPrint_2,&QAction::triggered,this,&MainWindow::on_actionPrint_triggered);

    //设置statusBar
    ui->statusBar->addPermanentWidget(&l_codec);

    //检查本地化打开defalut.md或defalut.zh.md
    QLocale loc;
    if(path!=nullptr)
        openFile(path);
    else if(loc.bcp47Name()=="zh"){
        openFile(":/default.zh.md");
        this->setWindowTitle("MarkDown Editor");
    }
    else{
        openFile(":/default.md");
        this->setWindowTitle("MarkDown Editor");
    }

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::openFile(const QString &path,const bool isForceCodec)
{//打开文件进程
    QFile f(path);
    if (!f.open(QIODevice::ReadOnly)) {
        QMessageBox::warning(this, windowTitle(),
                             tr("Could not open file %1: %2").arg(
                                 QDir::toNativeSeparators(path), f.errorString()));
        return;
    }
    m_filePath = path;

    //要先把数据取出来，用tried进行存储
    QByteArray fReadAll;
    QString tried="";
    fReadAll=f.readAll();
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    if(isForceCodec){
        QStringDecoder decorder(m_codec);
        tried=decorder(fReadAll);
    }
    else{
        if(QStringDecoder::encodingForData(fReadAll).has_value()){//自动检测成功了
            m_codec=QStringDecoder::encodingForData(fReadAll).value();
            QStringDecoder decorder(m_codec);
            tried=decorder(fReadAll);
        }else{
            m_codec=QStringDecoder::Utf8;
            QStringDecoder decorder(m_codec);
            tried=decorder(fReadAll);
            if(decorder.hasError()) {
                QMessageBox::warning(this, windowTitle(),
                                     tr("Could not detect file encording %1 open with utf-8.").arg(
                                         QDir::toNativeSeparators(path)));
            }
        }
#else
    tried=QString(fReadAll);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    }
#endif
    ui->editor->setPlainText(tried);
    this->setWindowTitle("MarkDown Editor - "+m_filePath);
    l_codec.setText(tr("Word count:%1").arg(ui->editor->toPlainText().size()));
}


bool MainWindow::isModified() const
{//检查是否更改过
    return ui->editor->document()->isModified();
}

void MainWindow::onFileNew()
{//新建文件
    if (isModified()) {
        QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(),
                             tr("You have unsaved changes. Do you want to create a new document anyway?"));
        if (button != QMessageBox::Yes)
            return;
    }

    m_filePath.clear();
    this->setWindowTitle("MarkDown Editor");
    ui->editor->setPlainText(tr("## New document"));
    ui->editor->document()->setModified(false);
}

void MainWindow::onFileOpen()
{//打开文件对话框
    if (isModified()) {
        QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(),
                             tr("You have unsaved changes. Do you want to open a new document anyway?"));
        if (button != QMessageBox::Yes)
            return;
    }

    QString path = QFileDialog::getOpenFileName(this,
        tr("Open File"), "", "MarkDown File (*.md *.markdown);;TxT File (*.txt);;All files(*.*)");
    if (path.isEmpty())
        return;
    openFile(path);
}

bool MainWindow::onFileSave()
{//保存文件
    if (m_filePath.isEmpty() || m_filePath.startsWith(":/")) {
        return onFileSaveAs();
    }
    QMimeDatabase db;
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    if(m_codec!=QStringEncoder::Utf8 && !db.mimeTypesForFileName(m_filePath)[0].inherits("application/vnd.oasis.opendocument.text")){//未使用UTF-8也不是ODF,以旧版File存储
        QFile f(m_filePath);
        if (!f.open(QIODevice::WriteOnly | QIODevice::Text))  {
            QMessageBox::warning(this, windowTitle(),
                                 tr("Could not write to file %1: %2").arg(
                                     QDir::toNativeSeparators(m_filePath), f.errorString()));
            return false;
        }
        QStringEncoder encorder(m_codec,QStringEncoder::Flag::WriteBom);
        f.write(encorder(ui->editor->toPlainText()));
    }else {
#endif
        QTextDocumentWriter writer(m_filePath);
        if(!writer.write(ui->textBrowser->document()))
            return false;
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    }
#endif


    //保存完成后去除*
    this->setWindowTitle("MarkDown Editor - "+m_filePath);
    //更新文件
    l_codec.setText(tr("File Saved"));
    ui->editor->document()->setModified(false);
    return true;
}

bool MainWindow::onFileSaveAs()
{//另存为文件
    QFileDialog fileDialog(this, tr("Save as..."));
    fileDialog.setAcceptMode(QFileDialog::AcceptSave);
    QStringList mimeTypes;
    mimeTypes << "text/plain"
#if QT_CONFIG(textodfwriter)
              << "application/vnd.oasis.opendocument.text"
#endif
#if QT_CONFIG(textmarkdownwriter)
              << "text/markdown"
#endif
              << "text/html";
    fileDialog.setMimeTypeFilters(mimeTypes);
#if QT_CONFIG(textmarkdownwriter)
    fileDialog.setDefaultSuffix("md");
#endif
    if (fileDialog.exec() != QDialog::Accepted)
        return false;
    m_filePath = fileDialog.selectedFiles().first();
    qDebug()<<m_filePath;
    return onFileSave();
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    //退出
    if (maybeSave())
        e->accept();
    else
        e->ignore();
}

bool MainWindow::maybeSave()
{//存不？
    if (!ui->editor->document()->isModified())
        return true;

    const QMessageBox::StandardButton ret =
        QMessageBox::warning(this, QCoreApplication::applicationName(),
                             tr("The document has been modified.\n"
                                "Do you want to save your changes?"),
                             QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
    if (ret == QMessageBox::Save)
        return onFileSave();
    else if (ret == QMessageBox::Cancel)
        return false;
    return true;
}

void MainWindow::ChangeFont()
{//更改编辑器字体
    bool ok;
    QFont fonta = QFontDialog::getFont(&ok);
    if(ok)
        ui->editor->setFont(fonta);
}


void MainWindow::Findsome()
{//查找
    bool isOK;
    search=QInputDialog::getText(this, tr("Search"),tr("Search what?"),QLineEdit::Normal,search,&isOK);
    if(isOK){
        if(!ui->editor->find(search)){
            if(!ui->editor->find(search,QTextDocument::FindBackward)){
                QMessageBox::warning(this, tr("Search"),
                            tr("Can not found %1").arg(search));
            }else{
                ui->textBrowser->find(search);
            }
        }else{
            ui->textBrowser->find(search);
        }
    }
}

void MainWindow::on_actionAbout_triggered()
{//关于
    QMessageBox::information(this,tr("About"),tr("Powered by XQQY Meow～Ver1.1"));
}

void MainWindow::on_actionWC_triggered()
{//字数统计
    QMessageBox::information(this,tr("Word count"),tr("Total word:%1").arg(ui->editor->toPlainText().size()));
}

void MainWindow::on_editor_selectionChanged()
{//当更改选区时，结束对webview的搜索
    ui->textBrowser->find("");
}

void MainWindow::on_actionPreview_toggled(bool arg1)
{//打开预览
    ui->textBrowser->setHidden(!arg1);
}

void MainWindow::on_actionView_mode_toggled(bool arg1)
{//打开预览
    ui->editor->setHidden(arg1);
}

void MainWindow::on_actionExit_triggered()
{//退出程序
    close();
}

//当用户拖动文件到窗口部件上时候，就会触发dragEnterEvent事件
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    qDebug()<<event->mimeData()->formats()<<"size"<<event->mimeData()->formats().size();
    #ifndef Q_OS_WIN32
    if (event->mimeData()->hasFormat("text/plain"))
    #endif
        event->acceptProposedAction();
}

//当用户放下这个文件后，就会触发dropEvent事件
void MainWindow::dropEvent(QDropEvent *event)
{
    qDebug()<<"drop file:"<<event->mimeData()->urls();
    if(event->mimeData()->urls().size()>1)
        QMessageBox::warning(this, tr("File Drops"),tr("Droping more than 1 file is not allowed"));
    else{
        if (isModified()) {
            QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(),
                                 tr("You have unsaved changes. Do you want to open a new document anyway?"));
            if (button != QMessageBox::Yes)
                return;
        }
        openFile(event->mimeData()->urls()[0].toLocalFile());
    }
}


void MainWindow::on_actionHow_triggered()
{//如何使用——打开初始文件
    if (isModified()) {
        QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(),
                             tr("You have unsaved changes. Do you want to open a help document anyway?"));
        if (button != QMessageBox::Yes)
            return;
    }
    QString fname;
    QLocale loc;
    if(loc.bcp47Name()=="zh")
        fname=":/default.zh.md";
    else
        fname=":/default.md";
    openFile(fname);
}

void MainWindow::on_editor_textChanged()
{//给窗口标题加个*+更改内容
    if(!this->windowTitle().endsWith("*"))
        this->setWindowTitle(this->windowTitle()+"*");
    ui->textBrowser->setMarkdown(ui->editor->toPlainText());
    l_codec.setText(tr("Word count:%1").arg(ui->editor->toPlainText().size()));
}

void MainWindow::on_actionReadUTF_8_triggered()
{//使用UTF-8编码
    if (isModified()) {
        QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(),
                             tr("You have unsaved changes. Do you want to open a help document anyway?"));
        if (button != QMessageBox::Yes)
            return;
    }
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    m_codec=QStringConverter::Utf8;
#endif
    openFile(m_filePath,true);

}

void MainWindow::on_actionReadGBK_triggered()
{//使用系统编码
    if (isModified()) {
        QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(),
                             tr("You have unsaved changes. Do you want to open a help document anyway?"));
        if (button != QMessageBox::Yes)
            return;
    }
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    m_codec=QStringConverter:System;
#endif
    openFile(m_filePath,true);
}

void MainWindow::on_actionSaveUTF_8_triggered()
{//使用UTF-8保存
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    m_codec=QStringConverter:System;
#endif
    onFileSave();
}

void MainWindow::on_actionSaveGBK_triggered()
{//以系统编码保存
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    m_codec=QStringConverter:System;
#endif
    onFileSave();
}

void MainWindow::on_editor_cursorPositionChanged()
{//更改行号
    QString line,column;
    line=QString("%1").arg(ui->editor->textCursor().block().layout()->lineForTextPosition(ui->editor->textCursor().positionInBlock()).lineNumber()+ui->editor->textCursor().block().firstLineNumber());
    column=QString("%1").arg(ui->editor->textCursor().positionInBlock());
    ui->statusBar->showMessage(tr("line:%1 column:%2").arg(line,column));
}

void MainWindow::on_actionShowHTML_triggered()
{//以HTMl显示
    ShowHtml sh(this,ui->editor->toPlainText());
    sh.exec();
}

void MainWindow::on_actionPrint_triggered()
{//打印
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
    QPrinter printer(QPrinter::HighResolution);
    QPrintPreviewDialog preview(&printer, this);
    connect(&preview, &QPrintPreviewDialog::paintRequested, this, &MainWindow::printPreview);
    preview.exec();
#else
    return;
#endif

}
void MainWindow::printPreview(QPrinter *printer)
{//打印预览
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
    ui->textBrowser->print(printer);
#else
    Q_UNUSED(printer);
#endif
}
